@tool
extends TileMapLayer


class_name BridgeTileMapLayer


## 对象从高地过度到低地
signal event_floor_high_to_low(tilemap: BridgeTileMapLayer, body: Node2D)
## 对象从低地过度到高地
signal event_floor_low_to_high(tilemap: BridgeTileMapLayer, body: Node2D)


## 高地的掩码
@export_flags_2d_physics var high_floor_mask: int = 0
## 需要检测的对象掩码
@export_flags_2d_physics var cross_layer_mask: int = 0


const flag_source: int = 1
const flag_coord: Vector2i = Vector2i(0, 0)


class UnitLayerData:
    var refcount: int
    var collision_mask: int

var unit_map: Dictionary[Node2D, UnitLayerData] = {}


func _ready() -> void:
    if tile_set == null:
        var bridge: Resource = load("res://Resource/Tile/BridgeTileSet.tres")
        tile_set = bridge.duplicate()

    if not Engine.is_editor_hint():
        var cells: Array[Vector2i] = get_used_cells_by_id(flag_source, flag_coord)
        for c in cells:
            create_floor_area2d(c)
            set_cell(c, 0, Vector2i(2, 2))

func create_floor_area2d(cell: Vector2i) -> void:
    var area2d: Area2D = Area2D.new()
    var collision2d: CollisionShape2D = CollisionShape2D.new()
    var shape: RectangleShape2D = RectangleShape2D.new()
    shape.size = tile_set.tile_size
    collision2d.shape = shape
    area2d.add_child(collision2d)
    area2d.position = cell * tile_set.tile_size + tile_set.tile_size / 2
    area2d.collision_layer = 0
    area2d.collision_mask = cross_layer_mask
    area2d.body_entered.connect(_on_unit_enter)
    area2d.body_exited.connect(_on_unit_exit)
    add_child(area2d)

func _on_unit_enter(body: Node2D) -> void:
    if body is CharacterBody2D:
        var data: UnitLayerData = unit_map.get(body)
        if data == null:
            data = UnitLayerData.new()
            data.collision_mask = body.collision_mask
            data.refcount = 0
            unit_map[body] = data
        data.refcount += 1

func _on_unit_exit(body: Node2D) -> void:
    if body is CharacterBody2D:
        var data: UnitLayerData = unit_map.get(body)
        if data != null:
            data.refcount -= 1
            if data.refcount < 1:
                var low_floor_mask: int = (high_floor_mask >> 1)
                # 未调整过才进行处理
                if data.collision_mask & high_floor_mask:
                    # "高 -> 低"
                    event_floor_high_to_low.emit(self, body)
                    body.collision_mask = (body.collision_mask & (~high_floor_mask)) | low_floor_mask
                    body.z_index -= 1
                else:
                    # "低 -> 高"
                    event_floor_low_to_high.emit(self, body)
                    body.collision_mask = (body.collision_mask & (~low_floor_mask)) | high_floor_mask
                    body.z_index += 1
                unit_map.erase(body)
